// 初始化需要的值不一样，Map需要的是一个二维数组，而Set 需要的是一维 Array 数组
/**
 * 特点
 * Map默认情况下不包含任何键，所有键都是开发人员添加进去的。不像Object原型链上有一些默认的键。
 * Map的键可以是任意类型数据，就连函数都可以。Object的键只能是String或Symbol。
 * Map的键值对个数可以轻易通过size属性获取，Object需要手动计算。
 * Map在频繁增删键值对的场景下性能要比Object好
 * 什么时候用Map?
 * 要添加的键值名和Object上的默认键值名冲突，又不想改名时，可以换用Map。
 * 需要String和Symbol以外的数据类型做键值时，用Map。
 * 键值对很多，有需要计算数量时，用Map。
 * 需要频繁增删键值对时，用Map。
 *
 * Map转为数组
 * 1. Array.from(map), 2. [...map]
 *
 * Map 和 WeakMap 之间的主要区别是后者允许对作为键的对象进行垃圾回收，从而防止内存泄漏
 */
function Map() {
  let items = {};
  this.size = 0;

  // 操作方法
  // has方法
  this.has = function(val) {
    return items.hasOwnProperty(val);
  };
  // set(key, val)方法
  this.set = function(key, val) {
    items[key] = val;
    this.size++;
  };
  // get(key)方法
  this.get = function(key) {
    return this.has(key) ? items[key] : undefined;
  };
  // delete(key)方法
  this.delete = function(key) {
    if (this.has(key)) {
      delete items[key];
      this.size--;
      return true;
    }
    return false;
  };
  // clear()方法
  this.clear = function() {
    items = {};
    this.size = 0;
  };
  // 遍历方法
  // keys()方法
  this.keys = function() {
    return Object.keys(items);
  };
  // values()方法
  this.values = function() {
    return Object.values(items);
  };
  // forEach(fn, context)方法
  this.forEach = function(fn, context = this) {
    for (let i = 0; i < this.size; i++) {
      let key = Object.keys(items)[i];
      let value = Object.values(items)[i];
      fn.call(context, value, key, items);
    }
  };
}

module.exports = Map;
